﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using SOWY.common;

///testing
using System.Data.Odbc;
using System.IO;

namespace SOWY
{
    public partial class MainForm : Form
    {
        private KeywordProcessing objKeywordProcessing;
        private DataOperations objDataOperation;
        private List<List<Task>> performedTasks;

        public MainForm()
        {
            objKeywordProcessing = new KeywordProcessing();
            objDataOperation = new DataOperations();
            performedTasks = new List<List<Task>>();
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            //this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 
            setupAutoComplete();
            loadHistory();
            loadAgenda();
            setFocusOnTxtCommand();
        }

        private void setFocusOnTxtCommand()
        {
            txtCommand.TabIndex = 0;
            txtCommand.Focus();
        }

        private void setupAutoComplete()
        {
            txtCommand.AutoCompleteMode = AutoCompleteMode.Suggest;
            txtCommand.AutoCompleteSource = AutoCompleteSource.CustomSource;
            txtCommand.AutoCompleteCustomSource.AddRange(GeneralConstant.KEY_POSSIBLE_CREATE);
            txtCommand.AutoCompleteCustomSource.AddRange(GeneralConstant.KEY_POSSIBLE_DELETE);
            txtCommand.AutoCompleteCustomSource.AddRange(GeneralConstant.KEY_POSSIBLE_UPDATE);

        }

        private void loadAgenda()
        {
            List<Task> tasks = objKeywordProcessing.processKeyword("display");
            int top = GeneralConstant.DESIGN_AGENDA_TOP;
            pnlAgenda.Controls.Clear();

            for (int lineNum = 0; lineNum < tasks.Count; lineNum++)
            {
                setupDateLabel(lineNum, ref top, tasks[lineNum].startDate.ToShortDateString(), tasks[lineNum].endDate.ToShortDateString());
                setupTaskLabel(ref top, tasks[lineNum].task);
            }
        }

        private void loadHistory()
        {
            DataOperations dataOper = new DataOperations();
            DataTable dt = dataOper.readLog();
            int numberOfRow = dt.Rows.Count;
            int startCount = 0;
            if (numberOfRow == 0)
                return;
            if (numberOfRow > GeneralConstant.DESIGN_AGENDA_HISTORY_MAX_COUNT)
                startCount = numberOfRow - GeneralConstant.DESIGN_AGENDA_HISTORY_MAX_COUNT;

            for (int i = startCount; i < numberOfRow; i++)
            {
                DataRow dr = dt.Rows[i];
                string action = dr[GeneralConstant.DATABASE_LOG_COLUMN_INDEX_ACTION].ToString();
                string task = dr[GeneralConstant.DATABASE_LOG_COLUMN_INDEX_TASK].ToString();
                string startDate = dr[GeneralConstant.DATABASE_LOG_COLUMN_INDEX_START_DATE].ToString();
                string endDate = dr[GeneralConstant.DATABASE_LOG_COLUMN_INDEX_END_DATE].ToString();
                Task objTask = new Task(task, DateTime.Parse(startDate), DateTime.Parse(endDate), action);
                string line = processInformation(objTask);
                txtInfo.AppendText(line);
            }
        }

        private string processInformation(Task task)
        {

            string line = task.task + " " + task.type;

            if ((task.startDate != DateTime.MinValue && task.endDate != DateTime.MinValue))
            {
                line += " from " + task.startDate.ToShortDateString() + " to " + task.endDate.ToShortDateString();
            }
            else if (task.startDate == DateTime.MinValue && task.endDate == DateTime.MinValue)
            {

            }
            else if (task.startDate == DateTime.MinValue)
            {
                line += " on " + task.endDate.ToShortDateString();
            }
            else if (task.endDate == DateTime.MinValue)
            {
                line += " on " + task.startDate.ToShortDateString();
            }
            line += "\n";
            return line;
        }

        private string getDateLabelText(string startDate, string endDate)
        {
            string text;
            string minValue = DateTime.MinValue.ToShortDateString();
            if (startDate.Equals(minValue) && endDate.Equals(minValue))
            {
                text = GeneralConstant.DESIGN_AGENDA_TO_DO_STRING;
            }
            else if (startDate.Equals(minValue))
            {
                text = endDate;
            }
            else if (endDate.Equals(minValue))
            {
                text = startDate;
            }
            else
            {
                text = startDate + " -- " + endDate;
            }
            return text;
        }

        private void setupTaskLabel(ref int top, string task)
        {
            Label objLabelTask = new Label();
            objLabelTask.AutoSize = true;
            objLabelTask.BackColor = System.Drawing.Color.Transparent;
            objLabelTask.Font = new System.Drawing.Font(GeneralConstant.DESIGN_AGENDA_FONT_FAMILY, GeneralConstant.DESIGN_AGENDA_TASK_FONT_SIZE, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            objLabelTask.ForeColor = System.Drawing.SystemColors.Control;
            objLabelTask.Location = new System.Drawing.Point(GeneralConstant.DESIGN_AGENDA_TASK_LEFT, top);
            //objLabelTask.Name = "lblContent";
            objLabelTask.Text = task;
            pnlAgenda.Controls.Add(objLabelTask);
            top += objLabelTask.Size.Height + GeneralConstant.DESIGN_AGENDA_TASK_MARGIN;
        }

        private void setupDateLabel(int lineNum, ref int top, string startDate, string endDate)
        {
            Label objLabelDate = new Label();
            objLabelDate.Text = getDateLabelText(startDate, endDate);
            if (!(lineNum > GeneralConstant.TO_DO_TASK && objLabelDate.Text.Equals(GeneralConstant.DESIGN_AGENDA_TO_DO_STRING)))
            {
                objLabelDate.AutoSize = true;
                objLabelDate.BackColor = System.Drawing.Color.Transparent;
                objLabelDate.Font = new System.Drawing.Font(GeneralConstant.DESIGN_AGENDA_FONT_FAMILY, GeneralConstant.DESIGN_AGENDA_DATE_FONT_SIZE, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                objLabelDate.ForeColor = System.Drawing.SystemColors.ControlLight;
                objLabelDate.Location = new System.Drawing.Point(GeneralConstant.DESIGN_AGENDA_DATE_LEFT, top);
                //objLabelDate.Name = "lblDate";
                pnlAgenda.Controls.Add(objLabelDate);
                top += objLabelDate.Size.Height;
            }
            else
            {
                top -= GeneralConstant.DESIGN_AGENDA_TASK_MARGIN;
            }
        }



        //private void Undo_Modified(Task objTask, string task, DateTime startDate, DateTime endDate)
        //{
        //    objDataOperation.toDatabase(GeneralConstant.KEY_DELETE, task, startDate, endDate);
        //    performedTasks.RemoveAt(performedTasks.Count - 1);
        //    Task objTask2 = performedTasks[performedTasks.Count - 1];
        //    string action2 = objTask.type;
        //    string task2 = objTask.task;
        //    DateTime startDate2 = objTask.startDate;
        //    DateTime endDate2 = objTask.endDate;
        //    objDataOperation.toDatabase(GeneralConstant.KEY_ADD, task2, startDate2, endDate2);
        //}

        private void checkUndoCommand(string command)
        {
            for (int i = 0; i < GeneralConstant.KEY_POSSIBLE_UNDO.Length; i++)
            {
                if (command == GeneralConstant.KEY_POSSIBLE_UNDO[i])
                {
                    undoAction();
                }
            }
        }

        private void checkExitCommand(string command)
        {
            for (int i = 0; i < GeneralConstant.KEY_POSSIBLE_EXIT.Length; i++)
            {
                if (command == GeneralConstant.KEY_POSSIBLE_EXIT[i])
                {
                    Environment.Exit(0);
                }
            }
        }

        private bool isError(List<Task> tasks)
        {
            if (tasks.Count == 0 || tasks[0].type.Equals(GeneralConstant.KEY_ERROR))
                return true;
            else
                return false;
        }

        //
        //Event handler 
        //
        private void txtCommand_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                string command = txtCommand.Text.ToLower().Trim();
                if (command.Length == 0)
                {
                    return;
                }
                checkExitCommand(command);
                checkUndoCommand(command);
                processCommand();
                loadAgenda();
            }
        }

        private void processCommand()
        {
            List<Task> list_feedback = objKeywordProcessing.processKeyword(txtCommand.Text.Trim());
            string output = "";
            if (isError(list_feedback))
            {
                output = getErrorMessage(list_feedback);
            }
            else
            {
                output = getFeedbackMessageAndLogging(list_feedback);
            }
            writeOutputOnInfoPanelAndClearCommand(output);
        }

        private string getFeedbackMessageAndLogging(List<Task> list_feedback)
        {
            string output = "";
            List<Task> taskList = new List<Task>();
            for (int i = 0; i < list_feedback.Count; i++)
            {
                Task task = list_feedback[i];
                if (GeneralConstant.KEY_ADD.Equals(task.type) || GeneralConstant.KEY_DELETE.Equals(task.type))
                {
                    taskList.Add(task);
                    objDataOperation.insertLog(task.type, task.task, task.startDate.ToShortDateString(), task.endDate.ToShortDateString());
                }
                else if (GeneralConstant.KEY_UPDATE.Equals(task.type))
                {
                    objDataOperation.insertLog(task.type, task.task, task.startDate.ToShortDateString(), task.endDate.ToShortDateString());
                    taskList.Add(task);
                    i++;
                    //defensive coding, prevent wrong assumption
                    Debug.Assert(i >= list_feedback.Count);
                    task = list_feedback[i];
                    taskList.Add(task);
                }
                output += processInformation(task);

            }
            performedTasks.Add(taskList);
            return output;
        }

        private void writeOutputOnInfoPanelAndClearCommand(string output)
        {
            txtInfo.AppendText(output);
            txtInfo.ScrollToCaret();
            txtCommand.Clear();
        }

        private string getErrorMessage(List<Task> list_feedback)
        {
            string output;
            if (list_feedback.Count == 0)
                output = GeneralConstant.INFO_DO_NOT_UNDERSTAND + "\n";
            else
                output = list_feedback[0].task;
            return output;
        }





        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            maximiseForm();
        }

        private void maximiseForm()
        {
            this.Show();
            this.WindowState = FormWindowState.Normal;
        }

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Q && e.Modifiers == Keys.Control)
            {
                minimiseForm();
            }
            else if (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control)
            {
                undoAction();
            }

        }

        private void minimiseForm()
        {
            notifyIcon.ShowBalloonTip(500);
            this.Hide();
        }

        private void undoAction()
        {
            if (performedTasks.Count == 0)
            {
                MessageBox.Show("No action to undo", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                List<Task> taskList = performedTasks[performedTasks.Count - 1];
                string output = "";
                foreach (Task objTask in taskList)
                {
                    // objTask = performedTasks[performedTasks.Count - 1];
                    string action = objTask.type;
                    string task = objTask.task;
                    DateTime startDate = objTask.startDate;
                    DateTime endDate = objTask.endDate;
                    if (action.Equals(GeneralConstant.KEY_ADD))
                    {
                        objDataOperation.toDatabase(GeneralConstant.KEY_DELETE, task, startDate, endDate);
                    }
                    else if (action.Equals(GeneralConstant.KEY_DELETE))
                    {
                        objDataOperation.toDatabase(GeneralConstant.KEY_ADD, task, startDate, endDate);
                    }
                    else if (action.Equals(GeneralConstant.KEY_UPDATE))
                    {
                        //Undo_Modified(objTask, task, startDate, endDate);
                    }
                    objDataOperation.deleteLog();
                    output = action + " [" + task + "] - This action is canceled\n";
                }
                writeOutputOnInfoPanelAndClearCommand(output);
                performedTasks.RemoveAt(performedTasks.Count - 1);
                loadAgenda();
            }
        }
    }
}
